using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Threading;
using SocketTool.Messengers.Interfaces;

namespace SocketTool.Messengers
{
    public class Messenger : IMessenger
    {
        private struct WeakActionAndToken
        {
            public WeakAction Action;

            public object Token;
        }

        private static readonly object CreationLock = new object();

        private static IMessenger _defaultInstance;

        private readonly object _registerLock = new object();

        private Dictionary<Type, List<WeakActionAndToken>> _recipientsOfSubclassesAction;

        private Dictionary<Type, List<WeakActionAndToken>> _recipientsStrictAction;

        private readonly SynchronizationContext _context = SynchronizationContext.Current;

        private bool _isCleanupRegistered;

        //
        // 摘要:
        //     Gets the Messenger's default instance, allowing to register and send messages
        //     in a static manner.
        public static IMessenger Default
        {
            get
            {
                if (_defaultInstance == null)
                {
                    lock (CreationLock)
                    {
                        if (_defaultInstance == null)
                        {
                            _defaultInstance = new Messenger();
                        }
                    }
                }

                return _defaultInstance;
            }
        }

        //
        // 摘要:
        //     Registers a recipient for a type of message TMessage. The action parameter will
        //     be executed when a corresponding message is sent.
        //     Registering a recipient does not create a hard reference to it, so if this recipient
        //     is deleted, no memory leak is caused.
        //
        // 参数:
        //   recipient:
        //     The recipient that will receive the messages.
        //
        //   action:
        //     The action that will be executed when a message of type TMessage is sent. IMPORTANT:
        //     If the action causes a closure, you must set keepTargetAlive to true to avoid
        //     side effects.
        //
        //   keepTargetAlive:
        //     If true, the target of the Action will be kept as a hard reference, which might
        //     cause a memory leak. You should only set this parameter to true if the action
        //     is using closures. See http://galasoft.ch/s/mvvmweakaction.
        //
        // 类型参数:
        //   TMessage:
        //     The type of message that the recipient registers for.
        public virtual void Register<TMessage>(object recipient, Action<TMessage> action, bool keepTargetAlive = false)
        {
            Register(recipient, null, receiveDerivedMessagesToo: false, action, keepTargetAlive);
        }

        //
        // 摘要:
        //     Registers a recipient for a type of message TMessage. The action parameter will
        //     be executed when a corresponding message is sent. See the receiveDerivedMessagesToo
        //     parameter for details on how messages deriving from TMessage (or, if TMessage
        //     is an interface, messages implementing TMessage) can be received too.
        //     Registering a recipient does not create a hard reference to it, so if this recipient
        //     is deleted, no memory leak is caused.
        //     However if you use closures and set keepTargetAlive to true, you might cause
        //     a memory leak if you don't call GalaSoft.MvvmLight.Messaging.Messenger.Unregister(System.Object)
        //     when you are cleaning up.
        //
        // 参数:
        //   recipient:
        //     The recipient that will receive the messages.
        //
        //   token:
        //     A token for a messaging channel. If a recipient registers using a token, and
        //     a sender sends a message using the same token, then this message will be delivered
        //     to the recipient. Other recipients who did not use a token when registering (or
        //     who used a different token) will not get the message. Similarly, messages sent
        //     without any token, or with a different token, will not be delivered to that recipient.
        //
        //   action:
        //     The action that will be executed when a message of type TMessage is sent. IMPORTANT:
        //     If the action causes a closure, you must set keepTargetAlive to true to avoid
        //     side effects.
        //
        //   keepTargetAlive:
        //     If true, the target of the Action will be kept as a hard reference, which might
        //     cause a memory leak. You should only set this parameter to true if the action
        //     is using closures. See http://galasoft.ch/s/mvvmweakaction.
        //
        // 类型参数:
        //   TMessage:
        //     The type of message that the recipient registers for.
        public virtual void Register<TMessage>(object recipient, object token, Action<TMessage> action,
            bool keepTargetAlive = false)
        {
            Register(recipient, token, receiveDerivedMessagesToo: false, action, keepTargetAlive);
        }

        //
        // 摘要:
        //     Registers a recipient for a type of message TMessage. The action parameter will
        //     be executed when a corresponding message is sent. See the receiveDerivedMessagesToo
        //     parameter for details on how messages deriving from TMessage (or, if TMessage
        //     is an interface, messages implementing TMessage) can be received too.
        //     Registering a recipient does not create a hard reference to it, so if this recipient
        //     is deleted, no memory leak is caused.
        //
        // 参数:
        //   recipient:
        //     The recipient that will receive the messages.
        //
        //   token:
        //     A token for a messaging channel. If a recipient registers using a token, and
        //     a sender sends a message using the same token, then this message will be delivered
        //     to the recipient. Other recipients who did not use a token when registering (or
        //     who used a different token) will not get the message. Similarly, messages sent
        //     without any token, or with a different token, will not be delivered to that recipient.
        //
        //   receiveDerivedMessagesToo:
        //     If true, message types deriving from TMessage will also be transmitted to the
        //     recipient. For example, if a SendOrderMessage and an ExecuteOrderMessage derive
        //     from OrderMessage, registering for OrderMessage and setting receiveDerivedMessagesToo
        //     to true will send SendOrderMessage and ExecuteOrderMessage to the recipient that
        //     registered.
        //     Also, if TMessage is an interface, message types implementing TMessage will also
        //     be transmitted to the recipient. For example, if a SendOrderMessage and an ExecuteOrderMessage
        //     implement IOrderMessage, registering for IOrderMessage and setting receiveDerivedMessagesToo
        //     to true will send SendOrderMessage and ExecuteOrderMessage to the recipient that
        //     registered.
        //
        //   action:
        //     The action that will be executed when a message of type TMessage is sent. IMPORTANT:
        //     If the action causes a closure, you must set keepTargetAlive to true to avoid
        //     side effects.
        //
        //   keepTargetAlive:
        //     If true, the target of the Action will be kept as a hard reference, which might
        //     cause a memory leak. You should only set this parameter to true if the action
        //     is using closures. See http://galasoft.ch/s/mvvmweakaction.
        //
        // 类型参数:
        //   TMessage:
        //     The type of message that the recipient registers for.
        public virtual void Register<TMessage>(object recipient, object token, bool receiveDerivedMessagesToo,
            Action<TMessage> action, bool keepTargetAlive = false)
        {
            lock (_registerLock)
            {
                Type typeFromHandle = typeof(TMessage);
                Dictionary<Type, List<WeakActionAndToken>> dictionary;
                if (receiveDerivedMessagesToo)
                {
                    if (_recipientsOfSubclassesAction == null)
                    {
                        _recipientsOfSubclassesAction = new Dictionary<Type, List<WeakActionAndToken>>();
                    }

                    dictionary = _recipientsOfSubclassesAction;
                }
                else
                {
                    if (_recipientsStrictAction == null)
                    {
                        _recipientsStrictAction = new Dictionary<Type, List<WeakActionAndToken>>();
                    }

                    dictionary = _recipientsStrictAction;
                }

                lock (dictionary)
                {
                    List<WeakActionAndToken> list;
                    if (!dictionary.ContainsKey(typeFromHandle))
                    {
                        list = new List<WeakActionAndToken>();
                        dictionary.Add(typeFromHandle, list);
                    }
                    else
                    {
                        list = dictionary[typeFromHandle];
                    }

                    WeakAction<TMessage> action2 = new WeakAction<TMessage>(recipient, action, keepTargetAlive);
                    WeakActionAndToken weakActionAndToken = default(WeakActionAndToken);
                    weakActionAndToken.Action = action2;
                    weakActionAndToken.Token = token;
                    WeakActionAndToken item = weakActionAndToken;
                    list.Add(item);
                }
            }

            RequestCleanup();
        }

        //
        // 摘要:
        //     Registers a recipient for a type of message TMessage. The action parameter will
        //     be executed when a corresponding message is sent. See the receiveDerivedMessagesToo
        //     parameter for details on how messages deriving from TMessage (or, if TMessage
        //     is an interface, messages implementing TMessage) can be received too.
        //     Registering a recipient does not create a hard reference to it, so if this recipient
        //     is deleted, no memory leak is caused.
        //
        // 参数:
        //   recipient:
        //     The recipient that will receive the messages.
        //
        //   receiveDerivedMessagesToo:
        //     If true, message types deriving from TMessage will also be transmitted to the
        //     recipient. For example, if a SendOrderMessage and an ExecuteOrderMessage derive
        //     from OrderMessage, registering for OrderMessage and setting receiveDerivedMessagesToo
        //     to true will send SendOrderMessage and ExecuteOrderMessage to the recipient that
        //     registered.
        //     Also, if TMessage is an interface, message types implementing TMessage will also
        //     be transmitted to the recipient. For example, if a SendOrderMessage and an ExecuteOrderMessage
        //     implement IOrderMessage, registering for IOrderMessage and setting receiveDerivedMessagesToo
        //     to true will send SendOrderMessage and ExecuteOrderMessage to the recipient that
        //     registered.
        //
        //   action:
        //     The action that will be executed when a message of type TMessage is sent. IMPORTANT:
        //     If the action causes a closure, you must set keepTargetAlive to true to avoid
        //     side effects.
        //
        //   keepTargetAlive:
        //     If true, the target of the Action will be kept as a hard reference, which might
        //     cause a memory leak. You should only set this parameter to true if the action
        //     is using closures. See http://galasoft.ch/s/mvvmweakaction.
        //
        // 类型参数:
        //   TMessage:
        //     The type of message that the recipient registers for.
        public virtual void Register<TMessage>(object recipient, bool receiveDerivedMessagesToo,
            Action<TMessage> action, bool keepTargetAlive = false)
        {
            Register(recipient, null, receiveDerivedMessagesToo, action, keepTargetAlive);
        }

        //
        // 摘要:
        //     Sends a message to registered recipients. The message will reach all recipients
        //     that registered for this message type using one of the Register methods.
        //
        // 参数:
        //   message:
        //     The message to send to registered recipients.
        //
        // 类型参数:
        //   TMessage:
        //     The type of message that will be sent.
        public virtual void Send<TMessage>(TMessage message)
        {
            SendToTargetOrType(message, null, null);
        }

        //
        // 摘要:
        //     Sends a message to registered recipients. The message will reach only recipients
        //     that registered for this message type using one of the Register methods, and
        //     that are of the targetType.
        //
        // 参数:
        //   message:
        //     The message to send to registered recipients.
        //
        // 类型参数:
        //   TMessage:
        //     The type of message that will be sent.
        //
        //   TTarget:
        //     The type of recipients that will receive the message. The message won't be sent
        //     to recipients of another type.
        public virtual void Send<TMessage, TTarget>(TMessage message)
        {
            SendToTargetOrType(message, typeof(TTarget), null);
        }

        //
        // 摘要:
        //     Sends a message to registered recipients. The message will reach only recipients
        //     that registered for this message type using one of the Register methods, and
        //     that are of the targetType.
        //
        // 参数:
        //   message:
        //     The message to send to registered recipients.
        //
        //   token:
        //     A token for a messaging channel. If a recipient registers using a token, and
        //     a sender sends a message using the same token, then this message will be delivered
        //     to the recipient. Other recipients who did not use a token when registering (or
        //     who used a different token) will not get the message. Similarly, messages sent
        //     without any token, or with a different token, will not be delivered to that recipient.
        //
        // 类型参数:
        //   TMessage:
        //     The type of message that will be sent.
        public virtual void Send<TMessage>(TMessage message, object token)
        {
            SendToTargetOrType(message, null, token);
        }

        //
        // 摘要:
        //     Unregisters a messager recipient completely. After this method is executed, the
        //     recipient will not receive any messages anymore.
        //
        // 参数:
        //   recipient:
        //     The recipient that must be unregistered.
        public virtual void Unregister(object recipient)
        {
            UnregisterFromLists(recipient, _recipientsOfSubclassesAction);
            UnregisterFromLists(recipient, _recipientsStrictAction);
        }

        //
        // 摘要:
        //     Unregisters a message recipient for a given type of messages only. After this
        //     method is executed, the recipient will not receive messages of type TMessage
        //     anymore, but will still receive other message types (if it registered for them
        //     previously).
        //
        // 参数:
        //   recipient:
        //     The recipient that must be unregistered.
        //
        // 类型参数:
        //   TMessage:
        //     The type of messages that the recipient wants to unregister from.
        public virtual void Unregister<TMessage>(object recipient)
        {
            Unregister<TMessage>(recipient, null, null);
        }

        //
        // 摘要:
        //     Unregisters a message recipient for a given type of messages only and for a given
        //     token. After this method is executed, the recipient will not receive messages
        //     of type TMessage anymore with the given token, but will still receive other message
        //     types or messages with other tokens (if it registered for them previously).
        //
        // 参数:
        //   recipient:
        //     The recipient that must be unregistered.
        //
        //   token:
        //     The token for which the recipient must be unregistered.
        //
        // 类型参数:
        //   TMessage:
        //     The type of messages that the recipient wants to unregister from.
        public virtual void Unregister<TMessage>(object recipient, object token)
        {
            Unregister<TMessage>(recipient, token, null);
        }

        //
        // 摘要:
        //     Unregisters a message recipient for a given type of messages and for a given
        //     action. Other message types will still be transmitted to the recipient (if it
        //     registered for them previously). Other actions that have been registered for
        //     the message type TMessage and for the given recipient (if available) will also
        //     remain available.
        //
        // 参数:
        //   recipient:
        //     The recipient that must be unregistered.
        //
        //   action:
        //     The action that must be unregistered for the recipient and for the message type
        //     TMessage.
        //
        // 类型参数:
        //   TMessage:
        //     The type of messages that the recipient wants to unregister from.
        public virtual void Unregister<TMessage>(object recipient, Action<TMessage> action)
        {
            Unregister(recipient, null, action);
        }

        //
        // 摘要:
        //     Unregisters a message recipient for a given type of messages, for a given action
        //     and a given token. Other message types will still be transmitted to the recipient
        //     (if it registered for them previously). Other actions that have been registered
        //     for the message type TMessage, for the given recipient and other tokens (if available)
        //     will also remain available.
        //
        // 参数:
        //   recipient:
        //     The recipient that must be unregistered.
        //
        //   token:
        //     The token for which the recipient must be unregistered.
        //
        //   action:
        //     The action that must be unregistered for the recipient and for the message type
        //     TMessage.
        //
        // 类型参数:
        //   TMessage:
        //     The type of messages that the recipient wants to unregister from.
        public virtual void Unregister<TMessage>(object recipient, object token, Action<TMessage> action)
        {
            UnregisterFromLists(recipient, token, action, _recipientsStrictAction);
            UnregisterFromLists(recipient, token, action, _recipientsOfSubclassesAction);
            RequestCleanup();
        }

        //
        // 摘要:
        //     Provides a way to override the Messenger.Default instance with a custom instance,
        //     for example for unit testing purposes.
        //
        // 参数:
        //   newMessenger:
        //     The instance that will be used as Messenger.Default.
        public static void OverrideDefault(IMessenger newMessenger)
        {
            _defaultInstance = newMessenger;
        }

        //
        // 摘要:
        //     Sets the Messenger's default (static) instance to null.
        public static void Reset()
        {
            _defaultInstance = null;
        }

        //
        // 摘要:
        //     Provides a non-static access to the static GalaSoft.MvvmLight.Messaging.Messenger.Reset
        //     method. Sets the Messenger's default (static) instance to null.
        public void ResetAll()
        {
            Reset();
        }

        private static void CleanupList(IDictionary<Type, List<WeakActionAndToken>> lists)
        {
            if (lists == null)
            {
                return;
            }

            lock (lists)
            {
                List<Type> list = new List<Type>();
                foreach (KeyValuePair<Type, List<WeakActionAndToken>> list2 in lists)
                {
                    foreach (WeakActionAndToken item in list2.Value
                        .Where((WeakActionAndToken item) => item.Action == null || !item.Action.IsAlive).ToList())
                    {
                        list2.Value.Remove(item);
                    }

                    if (list2.Value.Count == 0)
                    {
                        list.Add(list2.Key);
                    }
                }

                foreach (Type item2 in list)
                {
                    lists.Remove(item2);
                }
            }
        }

        private static void SendToList<TMessage>(TMessage message, IEnumerable<WeakActionAndToken> weakActionsAndTokens,
            Type messageTargetType, object token)
        {
            if (weakActionsAndTokens == null)
            {
                return;
            }

            List<WeakActionAndToken> source = weakActionsAndTokens.ToList();
            foreach (WeakActionAndToken item in source.Take(source.Count()).ToList())
            {
                IExecuteWithObject executeWithObject = item.Action as IExecuteWithObject;
                if (executeWithObject != null && item.Action.IsAlive && item.Action.Target != null &&
                    ((object) messageTargetType == null || (object) item.Action.Target.GetType() == messageTargetType ||
                     messageTargetType.GetTypeInfo().IsAssignableFrom(item.Action.Target.GetType().GetTypeInfo())) &&
                    ((item.Token == null && token == null) || (item.Token != null && item.Token.Equals(token))))
                {
                    executeWithObject.ExecuteWithObject(message);
                }
            }
        }

        private static void UnregisterFromLists(object recipient, Dictionary<Type, List<WeakActionAndToken>> lists)
        {
            if (recipient == null || lists == null || lists.Count == 0)
            {
                return;
            }

            lock (lists)
            {
                foreach (Type key in lists.Keys)
                {
                    foreach (WeakActionAndToken item in lists[key])
                    {
                        IExecuteWithObject executeWithObject = (IExecuteWithObject) item.Action;
                        if (executeWithObject != null && recipient == executeWithObject.Target)
                        {
                            executeWithObject.MarkForDeletion();
                        }
                    }
                }
            }
        }

        private static void UnregisterFromLists<TMessage>(object recipient, object token, Action<TMessage> action,
            Dictionary<Type, List<WeakActionAndToken>> lists)
        {
            Type typeFromHandle = typeof(TMessage);
            if (recipient == null || lists == null || lists.Count == 0 || !lists.ContainsKey(typeFromHandle))
            {
                return;
            }

            lock (lists)
            {
                foreach (WeakActionAndToken item in lists[typeFromHandle])
                {
                    WeakAction<TMessage> weakAction = item.Action as WeakAction<TMessage>;
                    if (weakAction != null && recipient == weakAction.Target &&
                        (action == null || action.GetMethodInfo().Name == weakAction.MethodName) &&
                        (token == null || token.Equals(item.Token)))
                    {
                        item.Action.MarkForDeletion();
                    }
                }
            }
        }

        //
        // 摘要:
        //     Notifies the Messenger that the lists of recipients should be scanned and cleaned
        //     up. Since recipients are stored as System.WeakReference, recipients can be garbage
        //     collected even though the Messenger keeps them in a list. During the cleanup
        //     operation, all "dead" recipients are removed from the lists. Since this operation
        //     can take a moment, it is only executed when the application is idle. For this
        //     reason, a user of the Messenger class should use GalaSoft.MvvmLight.Messaging.Messenger.RequestCleanup
        //     instead of forcing one with the GalaSoft.MvvmLight.Messaging.Messenger.Cleanup
        //     method.
        public void RequestCleanup()
        {
            if (_isCleanupRegistered)
            {
                return;
            }

            Action cleanupAction = Cleanup;
            if (_context != null)
            {
                _context.Post(delegate { cleanupAction(); }, null);
            }
            else
            {
                cleanupAction();
            }

            _isCleanupRegistered = true;
        }

        //
        // 摘要:
        //     Scans the recipients' lists for "dead" instances and removes them. Since recipients
        //     are stored as System.WeakReference, recipients can be garbage collected even
        //     though the Messenger keeps them in a list. During the cleanup operation, all
        //     "dead" recipients are removed from the lists. Since this operation can take a
        //     moment, it is only executed when the application is idle. For this reason, a
        //     user of the Messenger class should use GalaSoft.MvvmLight.Messaging.Messenger.RequestCleanup
        //     instead of forcing one with the GalaSoft.MvvmLight.Messaging.Messenger.Cleanup
        //     method.
        public void Cleanup()
        {
            CleanupList(_recipientsOfSubclassesAction);
            CleanupList(_recipientsStrictAction);
            _isCleanupRegistered = false;
        }

        private void SendToTargetOrType<TMessage>(TMessage message, Type messageTargetType, object token)
        {
            Type typeFromHandle = typeof(TMessage);
            if (_recipientsOfSubclassesAction != null)
            {
                foreach (Type item in _recipientsOfSubclassesAction.Keys.Take(_recipientsOfSubclassesAction.Count())
                    .ToList())
                {
                    List<WeakActionAndToken> weakActionsAndTokens = null;
                    if ((object) typeFromHandle == item || typeFromHandle.GetTypeInfo().IsSubclassOf(item) ||
                        item.GetTypeInfo().IsAssignableFrom(typeFromHandle.GetTypeInfo()))
                    {
                        lock (_recipientsOfSubclassesAction)
                        {
                            weakActionsAndTokens = _recipientsOfSubclassesAction[item]
                                .Take(_recipientsOfSubclassesAction[item].Count()).ToList();
                        }
                    }

                    SendToList(message, weakActionsAndTokens, messageTargetType, token);
                }
            }

            if (_recipientsStrictAction != null)
            {
                List<WeakActionAndToken> list = null;
                lock (_recipientsStrictAction)
                {
                    if (_recipientsStrictAction.ContainsKey(typeFromHandle))
                    {
                        list = _recipientsStrictAction[typeFromHandle]
                            .Take(_recipientsStrictAction[typeFromHandle].Count()).ToList();
                    }
                }

                if (list != null)
                {
                    SendToList(message, list, messageTargetType, token);
                }
            }

            RequestCleanup();
        }
    }
}